package space

import (
	"fmt"
	"src/zeus/common"
	"src/zeus/entity"
	"src/zeus/iserver"
	"src/zeus/linmath"
	"src/zeus/msgdef"
	"time"

	"src/zeus/logger"
)

type AOIEntityType int

const (
	AOI_Watcher AOIEntityType = 0
	AOI_Other   AOIEntityType = 1
	AOI_All     AOIEntityType = 2
)

// 最多这么多次Loop就进行一次同步
const EntityMaxSyncNum = 30

// IEntityCtrl 内部使用接口
type IEntityCtrl interface {
	onEnterSpace()
	onLeaveSpace()
}

// IEnterSpace 上层回调
type IEnterSpace interface {
	OnEnterSpace(isNew bool)
}

// ILeaveSpace 上层回调
type ILeaveSpace interface {
	OnLeaveSpace()
}

// iGameStateSender 发送完整的游戏状态信息
type iGameStateSender interface {
	SendFullGameState()
}

// iLateLooper 内部接口, Entity后处理
type iLateLooper interface {
	onLateLoop()
}

// iAOIUpdater 刷新AOI接口
type iAOIUpdater interface {
	updateAOI()
}

type iLooper interface {
	onLateLoop()
	updateAOI()
}

// IWatcher 观察者
type IWatcher interface {
	iserver.IEntity
	PostToClient(msgdef.IMsg) error
	//移除观察对象
	RemoveExtWatchEntity(o iserver.ICoordEntity)
}

var _ IBeWatcher = &Entity{}

type IBeWatcher interface {
	iserver.IEntity
	AddExtWatchEntity(o iserver.ICoordEntity, isUpdate2BeWatcher bool)
	RemoveExtWatchEntity(o iserver.ICoordEntity)
}

// Entity 空间中的实体
type Entity struct {
	entity.Entity
	Position *entity.PropInfo // Position 是 entity.Entity.IPropsContainer 内数据 的指针
	Rota     *entity.PropInfo
	//states *EntityStates

	space iserver.ISpace

	lastAOIPos    linmath.Vector3
	needUpdateAOI bool
	AOIReady      bool
	_isWatcher    bool

	enterList *common.MapList //进入我的AOI
	leaveList *common.MapList //离开我的AOI
	aoiList   *AOIListInfo    // 在我AOI的其他人

	//aoies       []AOIInfo       // 触发AOI事件的entity
	aoiIndex   uint8 // AOI层级
	needHide   bool  // 是否需要隐藏
	hide       bool  // 是否已经隐藏
	playerhide bool  // 是否对玩家隐藏
	// 还剩多少次操作才会同步
	SyncNum int

	//观察列表
	extWatchList map[uint64]*extWatchEntity

	basePropsDirty bool

	// entity链接相关
	linkTarget iserver.ICoordEntity // 链接的目标Entity
	linkerList map[uint64]iserver.ICoordEntity

	// entity托管相关
	entrustTarget iserver.IEntrustEntity // 委托的目标Entity
	entrustedList map[uint64]iserver.IEntrustEntity

	// CastToAll相关的消息缓存
	delayedCastMsgs []*delayedCastMsg
	// Loop结束的时候，用于生成广播消息的方法（主要用于技能有关的RPC消息）
	LoopSendMsgList []func()

	//延迟
	delay uint8
}

/*
AOIListInfo 实体身上的AOI数据
可以在上面设置一些属性
*/
type AOIListInfo struct {
	allaoies   []*common.MapList // 自己所有的AOIentity
	hideOthers bool              // 隐藏别人玩家 默认false (是否可以看到别人玩家)
}

func NewAOIListInfo() *AOIListInfo {
	info := &AOIListInfo{
		allaoies: make([]*common.MapList, 0, 2),
	}
	info.allaoies = append(info.allaoies, common.NewMapList())
	info.allaoies = append(info.allaoies, common.NewMapList())
	info.hideOthers = false
	return info
}
func (a *AOIListInfo) Push(o iserver.ICoordEntity) {
	if o == nil {
		return
	}
	var at AOIEntityType = AOI_Watcher
	if !o.IsWatcher() {
		at = AOI_Other
	}
	if a.allaoies[at].Exists(o) {
		return
	}
	a.allaoies[at].Push(o)
}

func (a *AOIListInfo) Remove(o iserver.ICoordEntity) {
	if o == nil {
		return
	}
	var at AOIEntityType = AOI_Watcher
	if !o.IsWatcher() {
		at = AOI_Other
	}
	if !a.allaoies[at].Exists(o) {
		return
	}

	a.allaoies[at].Remove(o)
}

func (a *AOIListInfo) Exists(o iserver.ICoordEntity) bool {
	if o == nil {
		return false
	}
	var at AOIEntityType = AOI_Watcher
	if !o.IsWatcher() {
		at = AOI_Other
	}
	return a.allaoies[at].Exists(o)
}

func (a *AOIListInfo) Walk(t AOIEntityType, cb func(data common.Keyer) bool) {
	if t == AOI_All {
		for _, v := range a.allaoies {
			v.Walk(cb)
		}
	} else {
		a.allaoies[t].Walk(cb)
	}
}

func (a *AOIListInfo) CanAdd(ownerid uint64, o iserver.ICoordEntity) bool {
	if o == nil {
		return false
	}
	var at AOIEntityType = AOI_Watcher
	if aoiowneruid := o.GetAOIOwnerUID(); a.hideOthers &&
		aoiowneruid != 0 &&
		aoiowneruid != ownerid {
		//如果是有主人的东西，也需要判断主人是不是玩家，我可不可以看到他；
		//我不能看见别的玩家
		return false
	}
	if !o.IsWatcher() {
		at = AOI_Other
	}
	if a.allaoies[at].Exists(o) {
		return false
	}
	//判断是观察者的人数
	if o.IsWatcher() && a.allaoies[at].Size() >= maxAOICount {
		return false
	}
	/*
		不是观察者的时候，需要知道对应的所属者是不是观察者；
		如果对应的观察者在AOI里，他也在；如果不在，他也不在；
	*/
	return true
}

// 是否可以看到别人玩家
func (this *AOIListInfo) SetHideOthersPlayer(v bool) {
	this.hideOthers = v
}

func (this *AOIListInfo) Size() (result int) {
	for _, li := range this.allaoies {
		result += li.Size()
	}
	return result
}

// AOIInfo aoi信息
type AOIInfo struct {
	isEnter bool
	entity  iserver.ICoordEntity
}

// extWatchEntity 额外关注列表
type extWatchEntity struct {
	entity iserver.ICoordEntity

	isInAOI            bool // 是否在AOI范围内
	isUpdate2BeWatcher bool // 是否同步信息给被观察者
}

// OnInit 构造函数
func (e *Entity) OnInit() {
	e.Entity.OnInit()
	// e.Position = e.GetPropRaw2(entitydef.PLAYER_Prop_Position)
	// if e.Position == nil {
	// 	panic(fmt.Errorf("Space Entity get Position prop is nil"))
	// }
	// e.Rota = e.GetPropRaw2(entitydef.PLAYER_Prop_Rot)
	// if e.Rota == nil {
	// 	panic(fmt.Errorf("Space Entity get Rota prop is nil"))
	// }

	e.lastAOIPos = *linmath.Vector3_Invalid()
	e.needUpdateAOI = false
	e.playerhide = false

	e.enterList = common.NewMapList()
	e.leaveList = common.NewMapList()
	//e.aoies = make([]AOIInfo, 0, 10)
	e.aoiList = NewAOIListInfo()
	e.needHide = false
	e.hide = false

	e.delayedCastMsgs = make([]*delayedCastMsg, 0, 1)

	//e.initStates()

	e._isWatcher = false
	e.extWatchList = make(map[uint64]*extWatchEntity)

	e.RegMsgProc(&EntityMsgProc{e: e})

}

// OnAfterInit 后代的初始化
func (e *Entity) OnAfterInit() {
	e.Entity.OnAfterInit()
	e.SetAOILayerIndex(0)
	e.onEnterSpace()
}

// OnDestroy 析构函数
func (e *Entity) OnDestroy() {
	e.Entity.OnDestroy()
	e.onLeaveSpace()
}

// GetSpace 获取所在的空间
func (e *Entity) GetSpace() iserver.ISpace {

	if e.space == nil {
		if e.GetSpaceID() == 0 {
			panic(fmt.Errorf("not space"))
		}

		spc := iserver.GetSrvInst().GetEntity(e.GetSpaceID())
		if spc == nil {
			logger.Errorf("GetSpace error spc is nil .eid = %d, sid = %d", e.GetID(), e.GetSpaceID())
			return nil
		}
		var ok = false
		e.space, ok = spc.(iserver.ISpace)
		if !ok {
			spc = iserver.GetSrvInst().GetEntity(e.GetSpaceID())
			logger.Error("iserver.GetSrvInst().GetEntity(e.GetSpaceID())", e.GetSpaceID())
		}
	}

	return e.space
}

func (e *Entity) onEnterSpace() {
	ic, ok := e.GetRealPtr().(IEnterSpace)
	if ok {
		ic.OnEnterSpace(true)
	}
	if e.IsWatcher() {

		//e.aoies = append(e.aoies, AOIInfo{true, e})
	}

}

func (e *Entity) onLeaveSpace() {
	//离开地图的时候，客户端不想要收到AOI对象离开的消息
	e.SetAOIReady(false)
	if e.GetSpace() != nil {
		e.GetSpace().RemoveFromCoord(e)
	}

	if e.IsWatcher() {
		//e.aoies = append(e.aoies, AOIInfo{false, e})

		e.clearExtWatchs()
		e.updateAOI()
	}
	ic, ok := e.GetRealPtr().(ILeaveSpace)
	if ok {
		ic.OnLeaveSpace()
	}
}

// Entity帧处理顺序
// 处理消息和业务逻辑, 在业务逻辑中会有RPC和CastToAll
// 更新坐标系中的位置
// Space更新所有Entity的AOI
// Space调用所有Entity的LateUpdate, 发送属性消息, 延迟发送消息和缓存的CastToAll消息

// OnLoop 循环调用
func (e *Entity) OnLoop() {
	e.SyncNum--

	e.Entity.DoMsg()
	// 上层的Loop,处理了战斗属性
	e.Entity.DoLooper()

	protoVec3 := e.Position.GetValue().(*linmath.Vector3)
	// pos := linmath.NewVector3(protoVec3.GetX(), protoVec3.GetY(), protoVec3.GetZ())
	e.updatePosCoord(*protoVec3)
	//自己Player属性
	if e.SyncNum <= 0 {
		e.Entity.ReflushSync()
	}
	li := e.LoopSendMsgList
	for _, f := range li {
		f()
	}
	// clear(e.LoopSendMsgList)
	e.LoopSendMsgList = e.LoopSendMsgList[0:0]
}

// onLateLoop 后处理
func (e *Entity) onLateLoop() {

	e.Entity.FlushDelayedMsgs()
	e.FlushBaseProps()
	// 真正发送所有消息
	e.FlushDelayedCastMsgs()
	if e.SyncNum <= 0 {
		e.SyncNum = EntityMaxSyncNum
	}
}

// 同步自己的脏数据到别的服务器上去，也发给客户端等
func (e *Entity) ReflushSync() {
	/*
		如果时机没到，就不同步
	*/
	if e.SyncNum <= 0 {
		e.Entity.ReflushSync()
	}
}

// IsSpaceEntity 是否是个SpaceEntity
func (e *Entity) IsSpaceEntity() bool {
	return true
}

func (this *Entity) GetNowTime() time.Time {
	return this.space.GetNowTime()
}

// GetPos 获取位置
func (e *Entity) GetPos() linmath.Vector3 {
	protoVec3 := e.Position.GetValue().(*linmath.Vector3)
	return *protoVec3
	// pos := linmath.NewVector3(protoVec3.GetX(), protoVec3.GetY(), protoVec3.GetZ())
	// return pos
}

// SetPos 设置位置
func (e *Entity) SetPos(pos linmath.Vector3) {

	protoVec3 := e.Position.GetValue().(*linmath.Vector3)
	if pos.X != protoVec3.GetX() || pos.Y != protoVec3.GetY() || pos.Z != protoVec3.GetZ() {
		// 这里的逻辑需要再考虑下
		tmp := pos
		e.SetCoordPos(pos)
		e.Position.SetValue(&tmp)
		//e.Position.SetValue(&protoMsg.Vector3{X: pos.X, Y: pos.Y, Z: pos.Z})
	}
}

// GetRota 获取旋转
func (e *Entity) GetRota() int32 {
	return e.Rota.GetValue().(int32)
}

// SetRota 设置旋转
func (e *Entity) SetRota(rota int32) {
	if rota == e.Rota.GetValue().(int32) {
		return
	}
	e.Rota.SetValue(rota)
}

func (e *Entity) GetModelRadius() float32 {
	return 0.0
}

// SetDelay 设置延迟的值
func (e *Entity) SetDelay(d uint8) {
	// logger.Debugf("SetDelay %d.", d)
	e.delay = d
}

// GetDelay 获取延迟的值
func (e *Entity) GetDelay() uint8 {
	return e.delay
}
